//
//  String+additions.swift
//  HIG
//
//  Created by arkin on 2016/10/21.
//  Copyright © 2016年 arkin. All rights reserved.
//

import UIKit
import Foundation

extension String {
    /// 统一解析正则
    ///
    /// - Parameter str: 正则
    /// - Returns: 结果
    public func predicateStr(str:String) -> Bool {
        let predicateStr = str
        let predicate =  NSPredicate(format: "SELF MATCHES %@" ,predicateStr)
        return predicate.evaluate(with: self)
    }
    
    /// 是否是邮箱
    ///
    /// - Returns: true是邮箱
    public func isEmail() -> Bool {
        return self.predicateStr(str: "^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$")
        
    }
    
    /// 是否是手机号（1开头判断）
    ///
    /// - Returns: true是
    public func isPhone() -> Bool{
        return self.predicateStr(str: "^1\\d{10}$")
    }
    
    /// 判断是否是用户名6到20位
    ///
    /// - Returns: true是
    public func isUserName() -> Bool {
        return self.predicateStr(str: "^[A-Za-z0-9]{6,20}+$")
    }
    
    
    /// 是否是中文
    ///
    /// - Returns: true是
    public func isChinese() -> Bool {
//        return self.predicateStr(str: "^[\\u4e00-\\u9fa5]+$")
        for (_, value) in self.enumerated() {
            
            if ("\u{4E00}" <= value  && value <= "\u{9FA5}") {
                return true
            }
        }
        
        return false
    }
    
    /// 判断是否是纯数字
    ///
    /// - Returns: true是
    public func isNumberStr() -> Bool {
        return self.predicateStr(str: "^\\d+$")
    }
    
    /// 是否是正确的密码
    ///
    /// - Returns: true是
    public func isValidPwd() -> Bool {
        return self.predicateStr(str: "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,30}$")
    }
    
    /// 是否是正确的薪资，整数或者小数，最多两位小数
    ///
    /// - Returns: true是
    public func isSalary() -> Bool {
        return self.predicateStr(str: "^[0-9]+(\\.[0-9]{1,2})?$")
    }
    
    /// 是否是正确的座机号
    ///
    /// - Returns: true是
    public func isTelePhone() -> Bool {
        return self.predicateStr(str: "(^$)|(^(0\\d{2})-(\\d{8})$)|(^(0\\d{3})-(\\d{7,8})$)|(^(0\\d{2})-(\\d{8})-(\\d+)$)|(^(0\\d{3})-(\\d{7,8})-(\\d+)$)|(^(0\\d{2,3})(\\d{7,8})$)")
    }
    
    ///去除html标签
    public func removeHtmlTag() -> String {
        let regex = try! NSRegularExpression(pattern: "<[^>]*>", options: [])
        return regex.stringByReplacingMatches(in: self, options: [],
                                              range: NSMakeRange(0, self.count),
                                              withTemplate: "").replacingOccurrences(of: "\n", with: "").replacingOccurrences(of: "\t", with: "")
    }
    /// 返回年龄
    ///
    /// - Returns: 年龄
    public func age() -> Int {
        if(self.isEmpty || self.count < 8){
            return 0
        }
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yy-MM-dd"
        let outputA:Date = dateFormatter.date(from: self)!
        let today = Date()
        let gregorian = NSCalendar(identifier: NSCalendar.Identifier.gregorian)
        let agea = gregorian?.components([.month, .day, .year], from: outputA, to: today, options:[])
        let agere = (agea?.year)!
        return agere > 0 ? agere : 0
    }
    
    /// 判断字符串是否为空，去除空格，换行
    public func customEmpty() -> Bool {
        let tmp = self.replacingOccurrences(of: " ", with: "").replacingOccurrences(of: "\n", with: "")
        return tmp.count > 0
    }
    
    public func removeFirstZero() -> String {
        func tmp(str:String) -> String{
            if str.count == 0{
                return ""
            }else{
                if str.subStringToIndex(toIndex: 1) == "0"{
                    if str.count > 2{
                        if str.subStringWithRange(start: 1, length: 1) == "."{
                            return str
                        }else{
                            return tmp(str:str.subStringFromIndex(fromIndex: 1))
                        }
                    }else{
                        return tmp(str:str.subStringFromIndex(fromIndex: 1))
                    }
                }
                return str
            }
        }
        return tmp(str: self)
    }
    
    /// 截取字符串
    ///
    /// - Parameter toIndex: 到第几个结束
    /// - Returns: 截取后的字符串
    public func subStringToIndex(toIndex:Int) -> String {
        if(self.count < toIndex || toIndex < 0){
            return self
        }
        return String(self.prefix(upTo: self.index(self.startIndex, offsetBy: toIndex)))
    }
    
    /// 截取字符串
    ///
    /// - Parameter fromIndex: 从第几个
    /// - Returns: 截取后的字符串
    public func subStringFromIndex(fromIndex:Int) -> String {
        if(self.count  < fromIndex || fromIndex < 0){
            return self
        }
        return String(self.suffix(from: self.index(self.startIndex, offsetBy: fromIndex)))
    }
    
    public func subStringWithRange(start:Int,length:Int) -> String {
        if(start < 0 || start > self.count || length < 0 || length >= self.count){
            return self
        }
        return String(self[self.index(self.startIndex, offsetBy: start)..<self.index(self.startIndex, offsetBy: start+length)])
    }
    
    public func sizeByFont(font:UIFont,size:CGSize) -> CGSize{
        
        let paraStyle = NSMutableParagraphStyle()
        paraStyle.lineBreakMode = .byCharWrapping
        let attrs = [NSAttributedString.Key.font: font,
                     NSAttributedString.Key.paragraphStyle: paraStyle,
                     NSAttributedString.Key.ligature: 1] as [NSAttributedString.Key : Any]
        let constraintRect = size
        let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: attrs, context: nil)
        return boundingBox.size
    }
    
    public func heightWithConstrainedWidth(width: CGFloat, font: UIFont) -> CGFloat {
        return sizeByFont(font: font, size: CGSize(width: width, height: .greatestFiniteMagnitude)).height
    }
    
    public func widthWithConstrainedWidth(height: CGFloat, font: UIFont) -> CGFloat {
        return sizeByFont(font: font, size: CGSize(width: .greatestFiniteMagnitude, height: height)).width
    }
    
    public func dataValue() -> Data {
        return self.data(using: .utf8)!
    }
    
    public func getFileSize() -> String  {
        var size: UInt64 = 0
        let fileManager = FileManager.default
        var isDir: ObjCBool = false
        let isExists = fileManager.fileExists(atPath: self, isDirectory: &isDir)
        // 判断文件存在
        if isExists {
            // 是否为文件夹
            if isDir.boolValue {
                // 迭代器 存放文件夹下的所有文件名
                let enumerator = fileManager.enumerator(atPath: self)
                for subPath in enumerator! {
                    // 获得全路径
                    let fullPath = self.appending("/\(subPath)")
                    do {
                        let attr = try fileManager.attributesOfItem(atPath: fullPath)
                        size += attr[FileAttributeKey.size] as! UInt64
                    } catch  {
                        print("error :\(error)")
                    }
                }
            } else { // 单文件
                do {
                    let attr = try fileManager.attributesOfItem(atPath: self)
                    size += attr[FileAttributeKey.size] as! UInt64
                    
                } catch  {
                    print("error :\(error)")
                }
            }
        }
        var str = ""
        let kb = size/1024
        if kb < 1024 {
            str = "\(kb)KB"
        } else {
            let mb = kb / 1024
            if mb < 1024 {
                str = "\(mb)MB"
            } else {
                str = "\(mb/1024)GB"
            }
        }
        return str
    }
    
    public func clearAllFiles() {
        let fileManager = FileManager.default
        var isDir: ObjCBool = false
        let isExists = fileManager.fileExists(atPath: self, isDirectory: &isDir)
        // 判断文件存在
        if isExists {
            // 是否为文件夹
            if isDir.boolValue {
                // 迭代器 存放文件夹下的所有文件名
                let enumerator = fileManager.enumerator(atPath: self)
                for subPath in enumerator! {
                    // 获得全路径
                    let fullPath = self.appending("/\(subPath)")
                    do {
                        try fileManager.removeItem(atPath: fullPath)
                    } catch  {
                        print("error :\(error)")
                    }
                }
            } else { // 单文件
                do {
                    try fileManager.removeItem(atPath: self)
                } catch  {
                    print("error :\(error)")
                }
            }
        }
    }
    
    public func jsonObject() -> [String: Any] {
        guard let data = self.data(using: .utf8) else {
            return [:]
        }
        do {
            if let jsonObj = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as?  [String: Any] {
                return jsonObj
            }
        } catch {}
        return [:]
    }
    
    /// 从String中截取出参数
    public var urlParameters: [String: AnyObject]? {
        // 截取是否有参数
        guard let urlComponents = NSURLComponents(string: self), let queryItems = urlComponents.queryItems else {
            return nil
        }
        // 参数字典
        var parameters = [String: AnyObject]()
        // 遍历参数
        queryItems.forEach({ (item) in
            // 判断参数是否是数组
            if let existValue = parameters[item.name], let value = item.value {
                // 已存在的值，生成数组
                if var existValue = existValue as? [AnyObject] {
                    existValue.append(value as AnyObject)
                } else {
                    parameters[item.name] = value as AnyObject
                }
            } else {
                parameters[item.name] = item.value as AnyObject
            }
        })
        return parameters
    }
    
    public func transformToPinyin() -> String {
        if self.count == 0{
            return ""
        }
        let tmp = self.subStringToIndex(toIndex: 1)
        let stringRef = NSMutableString(string: tmp) as CFMutableString
        CFStringTransform(stringRef,nil, kCFStringTransformToLatin, false) // 转换为带音标的拼音
        CFStringTransform(stringRef, nil, kCFStringTransformStripCombiningMarks, false) // 去掉音标
        let pinyin = stringRef as String
        if pinyin.count > 0{
            return pinyin.subStringToIndex(toIndex: 1)
        }
        return ""
    }
    
    /// 获取字符串指定宽度时每行的字符串
    ///
    /// - Parameters:
    ///   - font: 字体大小
    ///   - width: 指定宽度
    /// - Returns: 字符串数组
    public func lineStringArrary(font: UIFont, width: CGFloat) -> [String] {
        let attStr = NSMutableAttributedString.init(string: self)
        attStr.addAttribute(NSAttributedString.Key.font, value: font, range: NSRange(location: 0, length: self.count))
        let frameSetter = CTFramesetterCreateWithAttributedString(attStr)
        let path = CGMutablePath()
        path.addRect(CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
        let frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, nil);
        let lines = CTFrameGetLines(frame) as Array
        var lineStrArr = [String]()
        lines.forEach { (line) in
            let lineRef = line as! CTLine
            let lineRange = CTLineGetStringRange(lineRef)
            let range = NSRange(location: lineRange.location, length: lineRange.length)
            let lineStr = String(self[self.index(self.startIndex, offsetBy: range.location)..<self.index(self.startIndex, offsetBy: range.location+range.length)])
            lineStrArr.append(lineStr)
        }
        return lineStrArr
    }
    
}

extension NSAttributedString {
    public func heightWithConstrainedWidth(width: CGFloat) -> CGFloat {
        let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
        let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, context: nil)
        
        return boundingBox.height
    }
    
    public func widthWithConstrainedHeight(height: CGFloat) -> CGFloat {
        let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height)
        let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, context: nil)
        
        return boundingBox.width
    }
}
